---
description:
  This guide covers best practices for security, authentication, and permissions within the context of Headless CMS.
author: Bryant Gillespie
---

# Security Best Practices For Headless CMS Projects

> {{ $frontmatter.description }}

A [Headless CMS](https://directus.io/solutions/headless-cms), when coupled with statically-generated sites, are
architecture choices that are generally more secure than Traditional CMS because your content is separated from the
presentation layer. Given that users don't directly interact with a server to construct a page, there is a reduced
ability for malicious actors to attack the website. However, it is still very important that you follow good security
protocols to keep your data protected.

In this guide, we'll cover some best practices for keeping your Directus Headless CMS secure.

## Restrict Public Role

Directus makes it super easy to share your content with our REST and GraphQL APIs.

The Public role within [Access Control](/user-guide/user-management/users-roles-permissions#roles) defines what content
is available without authentication. To be safe, all permissions are turned off by default. This means that no data is
available via the API without providing a proper [access token](/reference/authentication#access-tokens). Your use case
may allow all data to be public, but it may instead require restricted access.

**If you do want to make data public, we recommend these guidelines.**

- On your public role, only enable read access.
- Consider defining a [Custom Permission](/user-guide/user-management/permissions#configure-custom-permissions) for read
  operations to control which items are available and which fields within those items consumers can see.

  ![The custom permissions interface for the Public role is displayed. The Item Permissions table is active and one Rule is active - "Status" Equals "Published".](https://cdn.directus.io/docs/v9/headless-cms/security-20230322/custom-permissions.webp)

  Standard read permissions grant access to ALL data within a collection which means the general public could see
  unpublished content you might not want them to see.

- Do not enable create, update, or delete access for collections within the Public role. This opens your instance up for
  attack from spammers and other bad actors.

## Create Scoped Roles For Specific Purposes

As a general security rule, you should only share the minimum amount of data that is needed to achieve your goal.

For an example website use case, you might have several different types of users and roles that need access to various
levels of data.

- **Website API** - role and user for reading content from the API (pages, posts, etc) and creating form submissions.
- **Guest Author** - restricted role where guest post authors can only update their own content.
- **Content Manager** - non-admin role that grants full CRUD access to all collections except business analytics.

For each of these roles, allow access only to the collections and specific CRUD operations that each role needs to
perform their function.

Our guide on [Content Approval Workflows](/guides/headless-cms/approval-workflows) is helpful for scoping roles and
permissions.

## Obscure Access Tokens and URLs

There are three ways to authenticate with Directus –
[Temporary Tokens (JWT), Session Tokens (JWT) or Static tokens](/reference/authentication#access-tokens).

Temporary Tokens and Session Tokens are generated by the login endpoint. They are short-lived and generally more secure.

Static tokens are set for each user and never expire. They are handy to use for server-to-server communication.

If you are using Static Tokens and your website or frontend is built using a static site generator (SSG) or calls your
API on the client side, then you could be exposing your access token.

To obscure your Directus Access Tokens and URL:

1. **Never store access tokens inside your code or repository.** Use a .env file to store secrets and sensitive
   credentials like access tokens.

2. **Call your API from the server-side**. Frontend frameworks like Next.js and Nuxt.js have "server" routes that you
   can setup that are only called from the server, never on the client.

   You can also use serverless functions or backend proxies to hide them from public view. Some website deployment
   platforms include serverless functions as part of their offering.

   - [Vercel Serverless Functions](https://vercel.com/docs/concepts/functions/serverless-functions)
   - [Netlify Functions](https://docs.netlify.com/functions/overview/)

## Be Careful When Granting Admin Access

In a typical Directus project, there’s only a small group of people that truly need the Administrator role. The
Administrator role provides full-access to CRUD+S Operations on every collection and rights to change any project
settings, roles, data models, etc.

When granting Admin access, make sure that it is only provided to those individuals who require it to perform their job
responsibilities. Too many Admins or granting Admin access to those who don’t truly need it can put the security of your
Directus instance at risk.

## Require Two-Factor Authentication and Secure Passwords

Many data breaches can be attributed back to sharing passwords or using the same password across many different sites.

While in the development phase of your project, it can certainly be easier and quicker to use weak passwords for testing
purposes.

But when it’s time to go to production and add all your different users, we recommend the following:

1. **Enable and enforce two-factor authentication.**

   Two-factor authentication can be enforced for each specific role by checking the Require 2FA field in a
   [role's settings](/user-guide/user-management/roles#configure-role-details).

   ![The Administrator role settings page is displayed. The Require 2FA form field is highlighted and enabled.](https://cdn.directus.io/docs/v9/headless-cms/security-20230322/2fa-role.webp)

   Individual users can enable two-factor authentication by checking the Two-Factor Authentication field on their own
   [user detail page](/user-guide/user-management/user-directory#user-details-page) and confirming their password.

   ![A sample user's detail page is shown. The Two-Factor Authentication form field is highlighted. ](https://cdn.directus.io/docs/v9/headless-cms/security-20230322/2fa-user.webp)

2. **Enable the Strong option for Auth Password Policy under
   [Project Settings > Security](/user-guide/settings/project-settings#security).**

   ![The Project Settings page is shown. The Security section is highlighted. Within the Security, section there are two fields shown: Auth Password Policy and Auth Login Attempts.](https://cdn.directus.io/docs/v9/headless-cms/security-20230322/security-project-settings.webp)

::: warning Use Different Project Names Between Environments

The project name is used in two-factor authentication for identification. Remember to set a different project name to
differentiate between environments to prevent the authenticator application from overriding the token for a different
environment.

For example:

| Environment | Project Name     |
| ----------- | ---------------- |
| Production  | Directus         |
| Staging     | Directus Staging |
| Development | Directus Dev     |

:::
